package data;

import java.util.LinkedList;
import java.util.List;

import org.apache.jena.atlas.lib.StrUtils;

import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ReadWrite;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.tdb.TDBFactory;

public class Local {

	private static String path = "D:\\dataset";

	/**
	 * Fetches the cities that are persisted in the local dataset
	 * 
	 * @return List of the current saved cities
	 */
	public List<String> getCities() {
		Dataset ds = TDBFactory.createDataset(path);
		ResultSet rs = null;
		List<String> cityResources = new LinkedList<String>();

		if (ds != null) {
			ds.begin(ReadWrite.READ);

			try {
				QueryExecution qExec = QueryExecutionFactory.create(
						"SELECT DISTINCT ?s where{?s ?p ?o.}", ds);
				rs = qExec.execSelect();

			} finally {
				ds.end();
			}

			List<QuerySolution> cities = ResultSetFormatter.toList(rs);

			for (QuerySolution s : cities)
				cityResources.add(s.getResource("s").toString());
		} else {
			System.out.println("No dataset found");
		}

		return cityResources;
	}

	/**
	 * Calculates rating for a given city based on the entries in the local
	 * dataset
	 * 
	 * @param uri
	 *            unique resource identifier of city for which the rating is
	 *            needed
	 * @return calculated rating
	 */
	public float getRating(String uri) {
		String ratinguri = "http://semtechminip1.org/hasRating";
		Dataset ds = TDBFactory.createDataset(path);
		float avgRating = -1;

		ds.begin(ReadWrite.READ);
		try {
			Resource city = ds.getDefaultModel().getResource(uri);
			Property hasRating = ds.getDefaultModel().getProperty(ratinguri);

			StmtIterator iter = city.listProperties(hasRating);

			int counter = 0;
			int ratingsum = 0;
			while (iter.hasNext()) {
				Literal rating = (Literal) iter.nextStatement().getObject();
				ratingsum += (Integer) rating.getValue();
				counter++;
			}
			avgRating = ratingsum / counter;

		} finally {
			ds.end();
		}

		return avgRating;
	}

	/**
	 * Writes a rating of a city into the local dataset
	 * 
	 * @param uri
	 *            unique resource identifier of city for which the rating is
	 *            needed
	 * @param rating
	 *            the rating for the city
	 */
	public void rate(String uri, int rating) {
		String ratinguri = "http://semtechminip1.org/hasRating";
		Dataset ds = TDBFactory.createDataset(path);

		ds.begin(ReadWrite.WRITE);
		try {
			Model m = ds.getDefaultModel();
			Resource city = m.getResource(uri);
			Property hasRating = ds.getDefaultModel().getProperty(ratinguri);
			m.add(m.createLiteralStatement(city, hasRating, rating));
			ds.commit();
		} finally {
			ds.end();
		}
	}

	public Model mergeWithLocalModel(Model tomerge) {
		Model m = ModelFactory.createDefaultModel();
		Dataset ds = TDBFactory.createDataset(path);
		ds.begin(ReadWrite.READ);
		try {
			m = tomerge.union(ds.getDefaultModel());
		} finally {
			ds.end();
		}
		return m;
	}
	
	public ResultSet getCitiesByTemperature(String meanProp, Model m) {
		String request = StrUtils.strjoinNL(
				"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>",
				"SELECT DISTINCT ?city ?meanTemp WHERE {", "?city " + meanProp
						+ " ?meanTemp.",
				"?city <http://semtechminip1.org/hasRating> ?x.", "}");

		Query query = QueryFactory.create(request);
		QueryExecution qexec = QueryExecutionFactory.create(query, m);

		ResultSet rs = null;
		return rs = qexec.execSelect();
	}
}
